/*
 * === ENUNCIADO ==
 * 
 * Implementar en ASM la funci'on "dir_size" que dado un puntero a la estructura
 * directorio obtiene la suma del taman~o de todos los archivos que lo componen
 * La estructura de directorios respecta s_dir_entry y s_file_entry
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

typedef enum e_entry { TYPE_FILE = 0, TYPE_DIR = 1 } entry;

typedef struct s_dir_entry {
  entry entry_type;
  void *next_entry;
  char name[8+3];
  void *first_entry;
} dir_entry; // __attribute__((packed))

typedef struct s_file_entry {
  entry entry_type;
  void *next_entry;
  char name[8+3];
  int attr;
  int size;
  void *data;
} file_entry; // __attribute__((packed)) 


/* Dibujo del ejemplo (es bocha importante hacer dibujos (en papel es mas facil (si lo es)))

 [root] --> NULL
       \
        [dir0] --> file0 --> [dir1] --> NULL
              \                    \
               \                    NULL
                \
                 file1 --> file2 --> [dir2] --> [dir3] --> NULL
                                           \          \
                                            \          file4
                                             file3
*/

extern size_t dir_size(dir_entry *dir);

void complete_dir(dir_entry *dir, char* name, void* next_entry, void* first_entry ) {
    strcpy(dir->name, name);
    dir->entry_type = TYPE_DIR;
    dir->next_entry = next_entry;
    dir->first_entry = first_entry;
}

void complete_file(file_entry *file, char* name, void* next_entry, int attr, int size, void* data ) {
    strcpy(file->name, name);
    file->entry_type = TYPE_FILE;
    file->next_entry = next_entry;
    file->attr = attr;
    file->size = size;
    file->data = data;
}

int main(int argc, char *argv[]) {
  
  printf("Antes que todo voy a ver los offsets:\n\n");
  
  printf("dir_entry size = %li\n\toffset entry_type = %li\n\toffset next_entry = %li\n\toffset name = %li\
  \n\toffset first_entry = %li\n\n",
	 sizeof(dir_entry),
	 offsetof(dir_entry,entry_type),
	 offsetof(dir_entry,next_entry),
	 offsetof(dir_entry,name),
	 offsetof(dir_entry,first_entry)
  );

  printf("file_entry size = %li\n\toffset entry_type = %li\n\toffset next_entry = %li\n\toffset name = %li\
  \n\toffset attr = %li\n\toffset size = %li\n\toffset data = %li\n\n",
	 sizeof(file_entry),
	 offsetof(file_entry,entry_type),
	 offsetof(file_entry,next_entry),
	 offsetof(file_entry,name),
	 offsetof(file_entry,attr),
	 offsetof(file_entry,size),
	 offsetof(file_entry,data)
  );

  printf("Bueno, ahora a laburar, sumemos el total de archivos:\n\n");
  
    dir_entry *root_dir, *dir0, *dir1, *dir2, *dir3;
    file_entry *file0, *file1, *file2, *file3, *file4, *file5;

    int total_size;
    size_t dir_entry_size = sizeof(dir_entry);
    size_t file_entry_size = sizeof(file_entry);

    // Allocate memory
    root_dir = malloc(dir_entry_size);
    dir0 = malloc(dir_entry_size);
    dir1 = malloc(dir_entry_size);
    dir2 = malloc(dir_entry_size);
    dir3 = malloc(dir_entry_size);
    file0 = malloc(file_entry_size);
    file1 = malloc(file_entry_size);
    file2 = malloc(file_entry_size);
    file3 = malloc(file_entry_size);
    file4 = malloc(file_entry_size);
    file5 = malloc(file_entry_size);
    
    // Initialize ROOT dir
    complete_dir(root_dir, "ROOT", NULL, dir0);
    complete_dir(dir0, "dir0", file0, file1 );
    complete_dir(dir1, "dir1", NULL, NULL );
    complete_dir(dir2, "dir2", dir3, file3 );
    complete_dir(dir3, "dir3", NULL, file4 );

    // Initialize files
    complete_file( file0, "file0.txt", dir1,  0, 100000, NULL );
    complete_file( file1, "file1.txt", file2, 0,  20000, NULL );
    complete_file( file2, "file2.txt", dir2,  0,   3000, NULL );
    complete_file( file3, "file3.txt", NULL,  0,    400, NULL );
    complete_file( file4, "file4.txt", file5, 0,     50, NULL );
    complete_file( file5, "file5.txt", NULL,  0,      6, NULL );

    // total size
    total_size = dir_size(root_dir); 
    printf("result: %d\n", total_size);

    // free willy
    free(root_dir);
    free(dir0);
    free(dir1);
    free(dir2);
    free(dir3);
    free(file0);
    free(file1);
    free(file2);
    free(file3);
    free(file4);
    free(file5);

    return 0;
}
